/**
  ******************************************************************
  * @file    main.c
  * @author  Merlin	
  * @version V1.0
  * @date    2022-6-20
  * @brief   关于TCS34725颜色识别传感器的彩球分拣装置	
  ******************************************************************
  * @attention
  * verimake 用于ch549的进阶控制学习
  *
  ******************************************************************
  */
 
#include <CH549_TCS34725.h>//TCS34725颜色识别相关设定
#include <CH549_IIC.h>     //I2C相关设定
#include <CH549_PWM.h>     //CH549的PWM相关设定
#include <CH549_GPIO.h>    //GPIO相关设定
#include <CH549_BMP.h>      //用于显示图片的头文件
#include <CH549_OLED.h>     //其中有驱动屏幕使用的函数
#include <CH549_SPI.h>      //CH549官方提供库的头文件，定义了一些关于SPI初始化，传输数据等函数
#include <CH549_DEBUG.h>   //CH549官方提供库的头文件，定义了一些关于主频，延时，串口设置，看门口，赋值设置等基础函数
#include <CH549_sdcc.H>	   //ch549的头文件，其中定义了单片机的一些特殊功能寄存器

//#define numLEDs 10                 //灯的个数
#define max3v(v1, v2, v3)   ((v1)<(v2)? ((v2)<(v3)?(v3):(v2)):((v1)<(v3)?(v3):(v1)))     //三个数中最大值
#define min3v(v1, v2, v3)   ((v1)>(v2)? ((v2)>(v3)?(v3):(v2)):((v1)>(v3)?(v3):(v1)))     //三个数中最小值

UINT8 box[4] = {40,60,78,98};  //控制分向舵机的PWM参数三组，例如第一个数值即为第一个盒子
COLOR_RGBC rgb;        //RGB相关结构体
COLOR_HSL  hsl;        //HSL相关结构体

int oled_colum;        //oled列
int oled_row;          //oled行
void setCursor(int column,int row);//屏幕输出函数
/********************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*********************************************************************/
void main(void)
{
  UINT8  r ,g ,b;
  UINT32 M = 0;
  UINT16 m = 0,n = 0,l = 0,i = 0;
  CfgFsys(); //CH549时钟选择配置
  mDelaymS(20);
  SPIMasterModeSet(3);          //SPI主机模式设置，模式3
  SPI_CK_SET(12);               //设置spi sclk 时钟信号为12分频
	OLED_Init();			            //初始化OLED  
	OLED_Clear();                 //将oled屏幕上内容清除
	setFontSize(8);               //设置文字大小
  TCS34725_Init();              //初始化TCS34725
  TCS34725_SetGain(TCS34725_GAIN_4X);      //设置TCS34725的增益
  TCS34725_SetIntegrationTime(TCS34725_INTEGRATIONTIME_24MS);            //设置TCS34725的积分时间，即通道最大值
  SetPWMClkDiv(255);                          //PWM时钟配置,Fsys/255,Fsys为12Mhz
  SetPWMCycle256Clk();                      //PWM周期 Fsys/255/256
  PWM_SEL_CHANNEL(PWM_CH1,Enable);          //使能CH1，即P2.4
  PWM_SEL_CHANNEL(PWM_CH3,Enable);          //使能CH3，即P2.2
  SetPWM1Dat(18);
  /* 主循环 */
  while (1)
  {
    TCS34725_GetRawData(&rgb);            //读取当前颜色数据，即RGBC
    //RGBtoHSL(&rgb, &hsl);               //转RGB为HSL
    r = rgb.r*255.0/rgb.c;   //将实际的RGB值读取出来，范围为0-255
    g = rgb.g*255.0/rgb.c;
    b = rgb.b*255.0/rgb.c;
    mDelaymS(20);
    setCursor(0,0);//设置printf到屏幕上的字符串起始位置
	  printf_fast_f("R : %u    ",m);
    setCursor(0,2);//设置printf到屏幕上的字符串起始位置
	  printf_fast_f("G : %u    ",n);
    setCursor(0,4);//设置printf到屏幕上的字符串起始位置
	  printf_fast_f("B : %u    ",l);
    setCursor(0,6);//设置printf到屏幕上的字符串起始位置
	  printf_fast_f("RGB.C : %u    ",rgb.c);
    
    if (rgb.c > 100)           //能检测到亮度时开始读取颜色值
       {

      if (i == 3)              //2次循环后再读取防抖动
      {
        if ((max3v(r,g,b) > 240) || (max3v(r,g,b) < 60)) //经过防抖动之后可能还是有数据异常的情况，再检测一次
        {
          i--;
        }else
        {
        m = r;         //读取当前RGB值
        n = g;
        l = b;
        }
      }
      i++;      
       }
    if (rgb.c < 100)           //亮度归零意味着小球经过监测点，开始根据读取到的RGB值进行判断
      {
         if (i != 0)           //仅判断一次
         {
            if (m > n && m > l)
            {
              M = M << 8 | box[0]; //红球
            }
            else if ((l - n > 10) && l > m && l > n)
            {
              M = M << 8 | box[1]; //蓝球
            }
            else if (n > m && n > l)
            {
              M = M << 8 | box[2]; //绿球
            }
            //else if ((l - n < 10) && l > m && l > m)
            //{
            //  M = M << 8 | box[3];
            //}
            else
            {
              M = M << 8 | box[3]; //白球
            }
         }
        i = 0;
      }
    SetPWM3Dat((unsigned char)(M >> 8*2)); //将第三个数据发送给舵机
  }
}

/********************************************************************
* 函 数 名       : putchar
* 函数功能       : 将printf映射到OLED屏幕输出上
* 输    入      : 字符串
* 输    出    	: 字符串
********************************************************************/
int putchar( int a)
{      
    //在光标处显示文字 a
    OLED_ShowChar(oled_colum,oled_row,a);
    //将光标右移一个字的宽度,以显示下一个字
    oled_colum+=6;
    
    /*当此行不足以再显示一个字时，换行.
    同时光标回到最边(列坐标=0).
    */
    if (oled_colum>122){oled_colum=0;oled_row+=1;}
    return(a);
}

/********************************************************************
* 函 数 名       : setCursor
* 函数功能		   : 设置光标（printf到屏幕上的字符串起始位置）
* 输    入       : 行坐标 列坐标(此处一行为8个像素，一列为1个像素,所以屏幕上共有8行128列)
* 输    出    	 : 无
********************************************************************/
void setCursor(int column,int row)
{
    oled_colum = column;
    oled_row = row;
}